home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 14.3 KB | 351 lines | [TEXT/CCL2] |
- ;;-*- Mode: Lisp; Package: CCL -*-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; pop-up-menu.lisp
- ;;
- ;;
- ;; ©1989, Apple Computer, Inc
- ;;
- ;; this file implements pop-up menus, according to the Apple standard.
- ;; it also shows how multiple-inheritance can be handy!
- ;;
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Mod History
- ;;
- ;; 04/28/93 mwp Release
- ;; 11/11/92 bill Straz'es patch to specify background color with :menu-body.
- ;;-------------- 2.0
- ;; 03/23/92 bill set-view-size needed to force an erase.
- ;; menu-select now works correctly for hierarchical pop-up menus
- ;; (which are not Human Interface Guidelines compliant).
- ;; ------------- 2.0f3
- ;; 10/18/91 bill optimize view-draw-contents a little.
- ;; Adjust position of pop up menu
- ;; 10/15/91 bill window-font -> view-font
- ;; Add the little System 7 triangle.
- ;;-------------- 2.0b3
- ;; 06/21/91 bill wkf's mod: Add foreground color for titles of pop up menus.
- ;;-------------- 2.0b2
-
- ;;;;;;;;;;;;;;;;;;
- ;;
- ;; packages, proclamations, and requires
- ;;
-
- (in-package :ccl)
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (export '(pop-up-menu selected-item) :ccl))
-
- (defclass pop-up-menu (menu dialog-item)
- ((width-correction :allocation :class :initform 0
- :accessor pop-up-menu-width-correction)
- (menu-rect :initform nil :accessor pop-up-menu-rect)
- (title-rect :initform nil :accessor pop-up-menu-title-rect)
- (default-item :initarg :default-item :initform 1
- :accessor pop-up-menu-default-item)
- (auto-update-default :initarg :auto-update-default :initform t
- :accessor pop-up-menu-auto-update-default)
- (item-display :initarg :item-display :initform :selection
- :accessor pop-up-menu-item-display))
- (:default-initargs
- :menu-title "Untitled"
- :view-font '("Chicago" 12 :plain)))
-
-
- ;;;;;;;;;;;;;;
- ;;
- ;; width-correction will be set each time a menu is installed.
- ;; the actual amount depends on the text of the menu-items
- ;; the instance sets width-correction to the correct value, and then
- ;; calls the usual size-defaulting function
- ;;
- ;;;;;;;;;;;;;;
-
-
- ;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; definitions for pop-up menus
- ;;
-
-
- (defmethod menu-title ((menu pop-up-menu))
- (dialog-item-text menu))
-
- (defmethod set-menu-title ((menu pop-up-menu) new-title)
- (set-dialog-item-text menu new-title))
-
- (defmethod install-view-in-window ((menu pop-up-menu) view)
- (declare (ignore view))
- (menu-install menu)
- (call-next-method)
- (size-rectangles menu)
- (invalidate-view menu))
-
- (defmethod set-view-size :after ((menu pop-up-menu) h &optional v)
- (declare (ignore h v))
- (size-rectangles menu)
- (invalidate-view menu t))
-
- (defmethod set-view-position :after ((menu pop-up-menu) h &optional v)
- (declare (ignore h v))
- (size-rectangles menu))
-
- (defmethod size-rectangles ((menu pop-up-menu))
- "does a lot of tweaking to get the thing to draw right"
- (let* ((my-pos (view-position menu))
- (my-size (add-points (view-size menu) #@(-1 -1)))
- (text (dialog-item-text menu))
- (title-offset (make-point (if (eql 0 (length text))
- 0
- (+ 8 (string-width
- text
- (or (view-font menu)
- (view-font (view-window menu))))))
- 0))
- (menu-rect (or (pop-up-menu-rect menu)
- (setf (pop-up-menu-rect menu) (make-record :rect))))
- (title-rect (or (pop-up-menu-title-rect menu)
- (setf (pop-up-menu-title-rect menu)
- (make-record :rect)))))
- (rset menu-rect :rect.topleft (add-points my-pos title-offset))
- (rset menu-rect :rect.bottomright (add-points my-pos my-size))
- (rset title-rect :rect.topleft my-pos)
- (rset title-rect :rect.bottomright (make-point (+ (point-h my-pos)
- title-offset)
- (+ (point-v my-pos)
- (point-v my-size)
- -4)))))
-
- (defmethod remove-view-from-window ((menu pop-up-menu))
- (menu-deinstall menu)
- (call-next-method)
- (without-interrupts
- (dispose-record (pop-up-menu-rect menu) :rect)
- (setf (pop-up-menu-rect menu) nil)
- (dispose-record (pop-up-menu-title-rect menu) :rect)
- (setf (pop-up-menu-title-rect menu) nil)))
-
- (defmethod view-draw-contents ((menu pop-up-menu) &aux (items (menu-items menu)))
- (let* ((pos (view-position menu))
- (text (dialog-item-text menu))
- (ti-rect (pop-up-menu-title-rect menu))
- (item-display (pop-up-menu-item-display menu)))
- (rlet ((a-rect :rect))
- (copy-record (pop-up-menu-rect menu) :rect a-rect)
- (with-pstrs ((mi-title (if (eq item-display :selection)
- (if items
- (menu-item-title
- (nth (- (pop-up-menu-default-item menu) 1)
- items))
- "<No Items>")
- (if (stringp item-display)
- item-display
- (format nil "~a" item-display)))))
- (with-fore-color (part-color menu :menu-title) ; 21-Jun-91 -wkf
- (with-back-color (part-color menu :menu-body) ; 10-Nov-92 -straz
- (unless (equal text "")
- (#_EraseRect :ptr ti-rect)
- (#_MoveTo :word (+ (point-h pos) 3)
- :word (- (rref a-rect rect.bottom) 8))
- (with-pstrs ((di-title text))
- (#_DrawString :ptr di-title)))
- ; (#_OffsetRect :ptr a-rect :long #@(0 -1))
- (#_FrameRect :ptr a-rect)
- (#_MoveTo :word (+ (rref a-rect rect.left) 3)
- :word (rref a-rect rect.bottom))
- (#_LineTo :word (rref a-rect rect.right)
- :word (rref a-rect rect.bottom))
- (#_LineTo :word (rref a-rect rect.right)
- :word (rref a-rect rect.top))
- (#_InsetRect :ptr a-rect :long #@(1 1))
- (#_FillRect :ptr a-rect :ptr *white-pattern*)
- (#_MoveTo :word (+ (rref a-rect rect.left) 3)
- :word (- (rref a-rect rect.bottom) 5))
- (with-clip-rect a-rect
- (#_DrawString :ptr mi-title)
- (#_MoveTo :word (- (rref a-rect :rect.right) (+ 4 11))
- :word (- (ash (+ (rref a-rect :rect.bottom) (rref a-rect :rect.top)) -1)
- 2))
- ; Draw the little triangle.
- (#_line :long #@(10 0))
- (#_line :long #@(-5 5))
- (#_line :long #@(-4 -4))
- (#_line :long #@(7 0))
- (#_line :long #@(-3 3))
- (#_line :long #@(-2 -2))
- (#_line :long #@(3 0))
- (#_line :long #@(-1 1)))))))
- (unless (dialog-item-enabled-p menu)
- (rlet ((ps :penstate))
- (with-item-rect (rect menu)
- (#_InsetRect :ptr rect :long #@(0 -1))
- (#_GetPenState :ptr ps)
- (#_PenPat :ptr *gray-pattern*)
- (#_PenMode :word 11)
- (#_PaintRect :ptr rect)
- (#_SetPenState :ptr ps))))))
-
- ;;;;;;;;;;;
- ;;
- ;; the usual dialog-item-default-size calculates the width from the
- ;; width-correction instance-variable, and the width of the dialog-item-text.
- ;; before calling the usual, we set width-correction to take into account
- ;; the width of the menu-items
- ;;
- ;; The usual version calculates the height from the font-height. We need
- ;; to increase this by four, to allow for a border.
- ;;
-
- (defmethod view-default-size ((menu pop-up-menu))
- (let* ((the-font (view-font menu))
- (item-display (slot-value menu 'item-display))
- (max-menu-width (max 20 (if (stringp item-display)
- (string-width
- (or item-display "")
- the-font)
- 0))))
- (setf (dialog-item-width-correction menu)
- (+ (if (equal "" (dialog-item-text menu)) 9 18)
- (dolist (m (menu-items menu) max-menu-width)
- (when (> (setq m (string-width (menu-item-title m)
- the-font))
- max-menu-width)
- (setq max-menu-width m)))))
- (add-points #@(19 4)
- (call-next-method))))
-
- (defmethod view-click-event-handler ((menu pop-up-menu) where)
- (declare (ignore where))
- (let ((no-text (equal (dialog-item-text menu) "")))
- (unless no-text
- (#_InvertRect :ptr (pop-up-menu-title-rect menu)))
- (menu-select menu 0)
- (if (eq (pop-up-menu-item-display menu) :selection)
- (view-draw-contents menu)
- (unless no-text
- (#_InvertRect :ptr (pop-up-menu-title-rect menu))))))
-
- ;Update the menu's items then displays the pop-menu. Default-item is the
- ;item which will come up selected when the menu is displayed.
- (defmethod menu-select ((menu pop-up-menu) num
- &aux selection
- selected-menu
- selected-menu-item
- (a-rect (pop-up-menu-rect menu))
- (pos (with-focused-view (view-container menu)
- (%local-to-global
- (wptr menu)
- (rref a-rect :rect.topleft)))))
- (declare (ignore num))
- (menu-update menu)
- (setq selection (#_PopUpMenuSelect
- :ptr (slot-value menu 'menu-handle)
- :word (+ (point-v pos) 1)
- :word (+ (point-h pos) 1)
- :word (or (pop-up-menu-default-item menu) 0)
- :long)
- ;we get the selected menu in case you want to break the rules
- ;and use heirarchical menus in a pop-up menu
- selected-menu (menu-object (ash (logand #xFFFF0000 selection) -16))
- selected-menu-item (logand #x0000FFFF selection))
- (unless (eq selected-menu-item 0)
- (when (pop-up-menu-auto-update-default menu)
- (setf (pop-up-menu-default-item menu)
- (if (eq selected-menu menu)
- selected-menu-item
- (let ((1st-level-submenu selected-menu))
- (loop
- (let ((owner (menu-owner 1st-level-submenu)))
- (if (eq owner menu)
- (return (1+ (position 1st-level-submenu (menu-items menu)))))
- (if (null owner)
- (return (pop-up-menu-default-item menu)))
- (setq 1st-level-submenu owner)))))))
- (menu-item-action
- (nth (- selected-menu-item 1) (menu-items selected-menu)))))
-
- (defmethod menu-install ((menu pop-up-menu))
- "Creates the actual Macintosh menu with all of the menu's current items."
- (let* ((menu-items (menu-items menu)))
- (apply #'remove-menu-items menu menu-items)
- (init-menu-id menu)
- (with-pstrs ((menu-title (menu-title menu)))
- (let ((menu-handle (#_NewMenu :word (slot-value menu 'menu-id)
- :ptr menu-title
- :ptr)))
- (#_InsertMenu :ptr menu-handle
- :word -1)
- (setf (slot-value menu 'menu-handle) menu-handle)))
- (let* ((colors (part-color-list menu)))
- (loop
- (unless colors (return))
- (set-part-color menu (pop colors) (pop colors))))
- (apply #'add-menu-items menu menu-items)))
-
- (defmethod menu-deinstall ((menu pop-up-menu))
- (let* ((*menubar-frozen* t))
- (call-next-method)))
-
- (defmethod selected-item ((menu pop-up-menu))
- (nth (- (pop-up-menu-default-item menu) 1) (menu-items menu)))
-
-
- (provide 'pop-up-menu)
-
- #|
- (setq my-pop-up
- (make-instance 'pop-up-menu
- :dialog-item-text "Wowie"
- :menu-items
- (list
- (make-instance 'menu-item
- :menu-item-title "item one"
- :menu-item-action #'(lambda ()
- (print 1)))
- (make-instance 'menu-item
- :menu-item-title "item two"
- :menu-item-action #'(lambda ()
- (print 2)))
- (make-instance 'menu-item
- :menu-item-title "item three"
- :menu-item-action #'(lambda ()
- (print 3)))
- (make-instance 'menu-item
- :menu-item-title "item fourteen"
- :menu-item-action #'(lambda ()
- (print 14))))))
-
- (setq my-pop-up-2
- (make-instance 'pop-up-menu
- :item-display "Wowie"
- :menu-items
- (list
- (make-instance 'menu-item
- :menu-item-title "item one"
- :menu-item-action #'(lambda ()
- (print 1)))
- (make-instance 'menu-item
- :menu-item-title "item two"
- :menu-item-action #'(lambda ()
- (print 2)))
- (make-instance 'menu-item
- :menu-item-title "item three"
- :menu-item-action #'(lambda ()
- (print 3)))
- (make-instance 'menu-item
- :menu-item-title "item fourteen"
- :menu-item-action #'(lambda ()
- (print 14))))))
-
-
- (setq my-dial (make-instance 'dialog
- :view-size #@(180 60)
- :window-title "Pop-up Menu Test"
- :view-subviews (list my-pop-up my-pop-up-2)))
-
-
- |#
-